use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::Path;
use walkdir::WalkDir;
use zip::write::{ExtendedFileOptions, FileOptions};
use zip::ZipWriter;
use zip::{CompressionMethod, DateTime}; // 引入扩展类型

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 定义路径（基于项目根目录）
    let project_root = Path::new("");
    let target_zip = project_root.join("rlearn.zip");
    let config_dir = project_root.join("config");
    let rlib_pattern = project_root.join("target/release/*.rlib");
    let exe_pattern = project_root.join("target/release/*.exe");
    let web_dir = project_root.join("web_site/dist");

    // 2. 删除旧ZIP文件
    if target_zip.exists() {
        fs::remove_file(&target_zip)?;
    }

    // 3. 创建ZIP写入器（适配zip 4.5.0）
    let file = fs::File::create(&target_zip)?;
    let mut zip = ZipWriter::new(file);

    // 解决方案1: 使用ExtendedFileOptions（推荐，支持更多元数据）
    let now: DateTime = DateTime::default_for_write(); // 获取当前UTC时间
    let options = FileOptions::<ExtendedFileOptions>::default()
        .compression_method(CompressionMethod::Deflated)
        .unix_permissions(0o755)
        .last_modified_time(now); // 现在类型匹配了

    // 解决方案2: 使用默认单元类型（简单场景）
    // let options = FileOptions::<()>::default()
    //     .compression_method(CompressionMethod::Deflated)
    //     .unix_permissions(0o755);

    // 5. 添加web内容到static目录
    add_dir_with_prefix(&mut zip, &options, &config_dir, "config")?;

    // 4. 添加根目录文件（.rlib和.exe）
    add_files_by_pattern(&mut zip, &options, &rlib_pattern)?;
    add_files_by_pattern(&mut zip, &options, &exe_pattern)?;

    // 5. 添加web内容到static目录
    add_dir_with_prefix(&mut zip, &options, &web_dir, "static")?;

    // 完成打包
    zip.finish()?;
    println!("打包成功：{}", target_zip.display());
    Ok(())
}

/// 按通配符模式添加文件到ZIP根目录
fn add_files_by_pattern(
    zip: &mut ZipWriter<fs::File>,
    options: &FileOptions<ExtendedFileOptions>, // 匹配泛型类型
    pattern: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
    let pattern_str = pattern.to_string_lossy();
    for entry in glob::glob(&pattern_str)? {
        let path = entry?;
        if path.is_file() {
            let file_name = path.file_name().ok_or("无效文件名")?.to_string_lossy().clone();
            zip.start_file(file_name.clone(), options.clone())?;
            let mut buf: Vec<u8> = Vec::new();
            File::open(path.clone())?.read_to_end(&mut buf)?;
            zip.write_all(&buf)?;
        }
    }
    Ok(())
}

/// 添加目录到ZIP的指定前缀目录
fn add_dir_with_prefix(
    zip: &mut ZipWriter<fs::File>,
    options: &FileOptions<ExtendedFileOptions>, // 匹配泛型类型
    dir: &Path,
    prefix: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    if !dir.exists() {
        eprintln!("警告：目录 {} 不存在，已跳过", dir.display());
        return Ok(());
    }

    let prefix_path = Path::new(prefix);
    zip.add_directory(prefix_path.to_string_lossy(), options.clone())?;
    for entry in WalkDir::new(dir).min_depth(1) {
        let entry = entry?;
        let path = entry.path();
        let relative_path = path.strip_prefix(dir)?;
        let zip_path = Path::new(prefix).join(relative_path);

        if path.is_dir() {
            zip.add_directory_from_path(zip_path, options.clone())?;
        } else {
            zip.start_file_from_path(zip_path, options.clone())?;
            let mut buf: Vec<u8> = Vec::new();
            File::open(path)?.read_to_end(&mut buf)?;
            zip.write_all(&buf)?;
        }
    }
    Ok(())
}
